import mineflayer from "mineflayer";
import { ContentManager } from "./ContentManager.js";
import { ActManager } from "./ActManager.js";
import { AIAPI } from "../type/llmType.js";
import { chatMsgRouter } from "../utils/chatMsgRouter.js";
import { LLMChatMessage } from "../type/llmType.js";
import { GameChatMsgType } from "../type/gameType.js";
import { toString } from "../utils/string/toString.js";
import { botInit } from "../utils/botInit.js";
import { delayMS } from "../utils/delay.js";
import { getStatePrompt } from "../utils/get/getState.js";
import { DebugCommand } from "./DebugCommand.js";
import { removeActCallString, formatActCallString } from "../utils/string/formatString.js";
import { actExample } from "./act/actExample.js";
import { idleHandler } from "./idle.js";
import vec3 from "vec3";

export class Bot {
  _bot: mineflayer.Bot = null as any;
  _botName: string = null as any;
  _content: ContentManager = null as any;
  _aiapi: AIAPI = null as any;
  _actManager: ActManager = null as any;
  _systemPrompt: string = "";
  _dataPath: string = "./bots/asistent";

  _getFullSystemPrompt(): string {
    const result =
      getStatePrompt(this._bot) + this._systemPrompt + this._actManager.getActDoc() + actExample;
    //console.log(getStatePrompt(this._bot));
    return result;
  }

  // 消息处理
  _messagesQueue: Array<LLMChatMessage> = [];
  _messageProcessing: boolean = false;
  _messageDelimiter: string = "\n";
  _messageDelay: number = 1000;
  _hiddenActString: boolean = false;
  async _processMessageQueue(): Promise<void> {
    if (this._messageProcessing) return;
    this._messageProcessing = true;
    console.log(
      `BOT[${this._bot.username}]开始处理消息 ${
        this._messageDelay >= 5 ? "延时" + this._messageDelay + "毫秒" : ""
      }`
    );
    if (this._messageDelay >= 5) await delayMS(this._messageDelay);
    try {
      while (this._messagesQueue.length > 0) {
        // 合并消息作为一个请求
        let mergedContent = "";
        while (this._messagesQueue.length > 0) {
          const msg = (this._messagesQueue.shift() as LLMChatMessage).content.trim();
          if (msg !== "") {
            mergedContent += msg + this._messageDelimiter;
          }
        }
        const mergedMessage: LLMChatMessage = {
          role: "user",
          content: mergedContent.trim(),
        };

        console.log(`BOT[${this._bot.username}]接受消息: ${mergedContent}`);
        // 调用 LLM
        const contents = this._content.getContents();
        contents.unshift({ role: "system", content: this._getFullSystemPrompt() });
        contents.push(mergedMessage);
        let result = await this._aiapi.chat(contents);

        this._content.addContent(mergedMessage);
        this._content.addContent({ role: "assistant", content: result });

        //TODO?: 函数调用
        let actCallResult: { content: string; toolName: string } = { content: "", toolName: "" };
        try {
          actCallResult = await this._actManager.executeAct(result);
        } catch (error) {
          actCallResult.content = `发生错误: ${error}`;
          console.error(`BOT[${this._bot.username}]执行行动时发生错误: ${error}`);
        }
        if (actCallResult.content && actCallResult.content.trim() !== "") {
          let actMessage: string = formatActCallString(
            actCallResult.content.trim(),
            actCallResult.toolName
          );
          this._messagesQueue.push({ role: "user", content: actMessage });
        }
        console.log(`BOT[${this._bot.username}]回复信息: ${result}`);
        if (this._hiddenActString) result = removeActCallString(result);
        this._bot.chat(result);
      }
    } catch (error) {
      console.error(`BOT[${this._bot.username}]接受消息时发生错误: ${error}`);
    } finally {
      this._messageProcessing = false;
    }
  }
  async handleMessage(content: string): Promise<void> {
    if (content.trim() === "") return;
    this._messagesQueue.push({ role: "user", content: content });
    await this._processMessageQueue();
  }
  async _handleDebugCommand(
    command: string,
    chatMode: string = "chat",
    userName?: string
  ): Promise<void> {
    DebugCommand.processCommand(this, command, chatMode, userName);
  }

  _idlePos: vec3.Vec3 = null as any;
  _idleNextChange: number = 0;
  async start(dataPath: string = this._dataPath) {
    this._dataPath = dataPath;
    botInit(dataPath, this);
    //TODO? 聊天信息
    this._bot.on("message", async (jsonMsg, position) => {
      if (
        (jsonMsg.translate === "chat.type.text" &&
          jsonMsg.toString().includes(`<${this._botName}>`)) ||
        jsonMsg.toString().includes("[DebugCommand]")
      )
        return; // 忽略自己的聊天消息
      const routed: GameChatMsgType | null = chatMsgRouter(jsonMsg);
      if (routed) {
        if (
          (routed.type === "chat" || routed.type === "whisper") &&
          routed.message &&
          routed.message.startsWith("$")
        )
          this._handleDebugCommand(routed.message.substring(1).trim(), routed.type, routed.name);
        else this.handleMessage(toString(routed));
      }
    });

    this._bot.on("physicsTick", () => {
      if (this._actManager._state === "空闲") {
        if (Date.now() >= this._idleNextChange) idleHandler(this);
      } else {
        this._idlePos = this._bot.entity.position.clone();
      }
    });
  }
}

const bot = new Bot();
// bot.start("./bots/nijikori_test");
// const bot1 = new Bot();
// bot.start("./bots/mono_test");

bot.start();
